home *** CD-ROM | disk | FTP | other *** search
- /* ------------------------------ BTC.CPP ------------------------------- */
-
- /*
- BTC V1.8 - The C++ Class Library for Novell's Btrieve Record Manager 5.10
- 1/25/94 (C) 1994 John C. Leon. All Rights Reserved.
-
- Written with and fully tested only under Borland C++ 3.1 and Btrieve for
- DOS 5.10 ONLY, with all Btrieve patches available thru the date of this
- file applied.
-
- NOTE: Programs using this class library and its related functions
- should #include "btc.hpp", and be linked with BTCS.LIB (small model)
- or BTCL.LIB (large model).
-
- There is no need to include Novell's TURCBTRV.C file when using
- BTC, as the universal Btrieve call is included in the BTC libraries,
- and is declared in BTC.HPP.
-
- COMPILATION NOTES: WORD ALIGNMENT MUST BE OFF!
- "TREAT ENUMS AS INT" MUST BE CHECKED!
-
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- extern "C" { int BTRV(int, void*, void*, int*, void*, int); }
-
- /* Misc Types */
- /* ------------------------------------------------------------------------ */
- typedef unsigned char byte;
- enum boolean {false, true};
- typedef char FNameStr[80]; //79 + null pad for a Btrieve filename
-
- /* Btrieve KEY ATTRIBUTES */
- /* ------------------------------------------------------------------------ */
- enum KEY_FLAGS {
- Duplicates = 1, Modifiable = 2, Binary = 4, Null = 8,
- Segmented = 16, AltCol = 32, Descending = 64,
- Supplemental = 128, ExtType = 256, Manual = 512
- };
-
- /* Btrieve KEY TYPES */
- /* ------------------------------------------------------------------------ */
- enum KEY_TYPES {
- BString = 0, BInteger, BFloat, BDate, BTime, BDecimal,
- BMoney, BLogical, BNumeric, BBFloat, BLString, BZString,
- BUnsBinary = 14, BAutoInc
- };
-
- /* Btrieve FILE OPEN MODES */
- /* ------------------------------------------------------------------------ */
- enum OPEN_MODE {
- Exclusive = -4, Verify, ReadOnly, Accel, Normal
- };
-
- /* Btrieve FILE FLAGS */
- /* ------------------------------------------------------------------------ */
- enum FILE_FLAGS {
- VarLength = 1, BlankTrunc, PreAllocate = 4, DataComp = 8,
- KeyOnly = 16, Free10 = 64, Free20 = 128, Free30 = 192
- };
-
- /* Btrieve OP CODES */
- /* ------------------------------------------------------------------------ */
- enum OP_CODE {
- BOpen, BClose, BInsert, BUpdate, BDelete, BGetEqual,
- BGetNext, BGetPrev, BGetGr, BGetGrEq, BGetLess, BGetLessEq,
- BGetFirst, BGetLast, BCreate, BStat, BExtend, BSetDosDir,
- BGetDosDir, BBegTran, BEndTran, BAbortTran, BGetPos, BGetDirect,
- BStepNext, BStop, BVersion, BUnlock, BReset, BSetOwner,
- BClearOwner, BCrSuppIdx, BDropSuppIdx, BStepFirst, BStepLast, BStepPrev,
- BGetNextExt, BGetPrevExt, BStepNextExt, BStepPrevExt, BInsertExt,
- BGetKey = 50
- };
-
- /* Owner-Name Related Types */
- /* ------------------------------------------------------------------------ */
- typedef char OwnerName[9]; //8 chars max plus null
- enum OwnerAccess {RQ, RO, RQENC, ROENC};
-
- /* Selected Btrieve ERROR CODES */
- /* ------------------------------------------------------------------------ */
- typedef enum BTC_ERR_CODES {
- FileNotOpen = 3, DataBufferLength = 22,
- InvalidKeyNumber = 6, RejectCount = 60,
- DiffKeyNumber = 7, IncorrectDesc = 62,
- InvalidPosition = 8, FilterLimit = 64,
- EndofFile = 9, IncorrectFldOff = 65,
- FileNotFound = 12, LostPosition = 82,
- BtrieveNotLoaded = 20
- };
-
- /* Btrieve EXTENDED OPS COMP CODES/BIAS */
- /* ------------------------------------------------------------------------ */
- const byte
- Equal = 1, UseAltColl = 32,
- GreaterThan = 2, UseField = 64,
- LessThan = 3, UseNoCase = 128,
- NotEqual = 4,
- GrOrEqual = 5,
- LessOrEqual = 6;
-
- /* Btrieve EXTENDED OPS LOGIC CONSTANTS */
- /* ------------------------------------------------------------------------ */
- const int NoFilter = 0;
- const char LastTerm = 0, NextTermAnd = 1, NextTermOr = 2; //As chars, can't
- //make an enum.
-
- /* Other BTC-specific Constants */
- /* ------------------------------------------------------------------------ */
- const int
- NotRequired = 0, //Dummy for BTRV calls where int not req'd.
- MaxFixedRecLength = 4090, //Btrieve limits fixed rec length for std
- MaxKBufferLength = 255, //files to 4090. Max key size is 255.
- None = 0, Drop = 1, Retain = 2, //These 3 used in CloneFile function.
- MaxExtDBufferLength = 32767, //May be used in future for ext. calls.
- MaxFileSpecLength = 665,
- MaxNumSegments = 24,
- KeySpecSize = 16;
-
- /* Other BTC-specific Variables */
- /* ------------------------------------------------------------------------ */
- int BStatus = 0, //Global Btrieve status variable.
- VarNotRequired = 0; //Dummy parameter.
- byte VarPosBlk[128]; //Dummy used in ops that don't pass or
- //return a position block.
-
- /* ------------------------------------------------------------------------ */
- /* BTC DATA TYPES */
- /* ------------------------------------------------------------------------ */
- /* ------------------------------------------------------------------------ */
-
- /* Data types for TRecMgr class */
- /* ------------------------------------------------------------------------ */
- struct TBTVersion {
- int Number;
- int Rev;
- char Product;
- };
-
- class TBTRecMgr {
- protected:
- boolean BtrieveLoaded;
- TBTVersion Version;
- char VerString[10];
- public:
- TBTRecMgr();
- char* GetVersion() { return VerString; };
- virtual int BT( OP_CODE OpCode, int Key = 0 );
- virtual ~TBTRecMgr() { };
- };
-
- /* Data types for BBase class */
- /* ------------------------------------------------------------------------ */
-
- // TACS and TAltColSeq are for alternate collating sequences
-
- //TACS is for the actual alternate collating sequence itself
- struct TACS {
- byte Header; //Header always equals 0xAC
- char Name[8]; //not DOS filename, but name embedded in file
- byte Table[256];
- };
-
- //TAltColSeq is the class
- class TAltColSeq {
- public:
- TACS Spec;
- TAltColSeq() { };
- TAltColSeq(FNameStr SpecName);
- virtual ~TAltColSeq() { };
- };
-
- union TKeySpec { // Data type for a Btrieve key spec; 'sent' Keyspec
- struct {
- int KeyPos;
- int KeyLen;
- int KeyFlags;
- byte NotUsed[4]; // Tho not used in a create call, these 4 bytes
- byte ExtKeyType; // return number of unique recs in key after a
- byte NullValue; // stat call.
- byte Reserved[4];
- } SKeySpec;
- struct {
- int Irrelevant[3]; //This struct gives ability, on return from a
- unsigned long NumUnique; //stat call, to directly read the number of
- } RKeySpec; //unique records for a key.
- byte Entire[16];
- };
-
- struct TKeyList {
- TKeySpec KeySpec;
- TKeyList *Next;
- };
-
- struct SFileSpec {
- unsigned int RecLen;
- int PageSize;
- int NumKeys;
- unsigned int NumRecs[2];// an array of int, w/high int second
- int FileFlags;
- byte Reserved[2];
- int PreAlloc; //On return from stat, this area holds UnusedPgs.
- TKeySpec KeyArray[24]; //Technically, the KeyArray and AltColSpec merely
- TACS AltColSpec; //allocate space in a buffer of this data type, as it is unknown
- }; //it is unknown exactly how many key specs there
- //will be, or whether there will be an alternate
- //collating sequence.
-
- struct RFileSpec {
- byte Irrelevant[14];
- unsigned int UnusedPgs; //great after a stat call; corresponds to PreAlloc
- }; //field in struct SFileSpec
-
- union TFileSpec { //full definition of a Btrieve filespec
- SFileSpec FileSpec;
- RFileSpec ReturnFileSpec;
- byte Entire[MaxFileSpecLength];
- };
-
- class CFileSpec { //Useful in programs that use the CreateFile fcn.
- public:
- TFileSpec *Specs;
- TKeyList *KeyList;
- CFileSpec();
- CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
- TKeyList *AKeyList=NULL, int FileFlags=0, int PreAlloc=0);
- ~CFileSpec();
- };
-
- /* In base object, no buffer is allo-
- cated in constructor, and the
- BT function is nearly abstract.
- Create a descendant class by adding
- a data buffer/struct and key buffer,
- and you're all set. You'll surely
- also override the constructor,
- destructor, and BT functions. */
- class BBase {
- protected:
- byte PosBlk[128];
- public:
- TFileSpec Specs;
- FNameStr BFileName;
- int IsOpen;
- int SpecLength;
- long NumRecs;
- int NumSegs;
- boolean HasAltCol;
- boolean IsVariableLength;
- boolean HasOwner;
- OwnerName Owner;
- char AltColName[9]; //8 for largest name, 1 for null
- int DBufferLen;
- BBase() { };
- BBase(FNameStr UserFileName, OPEN_MODE OpenMode=Normal, OwnerName owner="");
- virtual int Open(OPEN_MODE OpenMode=Normal);
- virtual int Close();
- virtual int Stat();
- virtual int BT(OP_CODE OpCode, int Key=0) { return 0; };
- virtual ~BBase();
- };
-
- /* Data types for BFile class */
- /* ------------------------------------------------------------------------ */
- class BFile: public BBase {
- public:
- byte *DBuffer;
- byte *KBuffer;
- unsigned int DBufferSize;
- BFile();
- BFile(FNameStr UserFileName, OPEN_MODE OpenMode = Normal, OwnerName owner = "",
- unsigned int dBufferSize = MaxFixedRecLength);
- virtual int BT(OP_CODE OpCode, int Key = 0);
- virtual int AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile="");
- virtual ~BFile();
- BFile& operator++(); //Overload prefix operators to do step
- BFile& operator++(int); //next(++) and step previous (--).
- BFile& operator--(); //Overload postfix operators to do
- BFile& operator--(int); //insert(++) and delete (--).
- BFile& operator=(BFile& bfixed); //Overload assignment operator to
- //copy data buffer to destination.
- //CloneFile() needs write access to *DBuffer and *KBuffer.
- friend int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option,
- OwnerName Owner);
- };
-
-
- /* ------------------------------------------------------------------------ */
- /* METHOD DEFINITIONS */
- /* ------------------------------------------------------------------------ */
- /* ------------------------------------------------------------------------ */
-
- TBTRecMgr::TBTRecMgr() {
- int sizeVersion = sizeof(Version);
- BtrieveLoaded =
- (BTRV(BVersion, VarPosBlk, &Version, &sizeVersion, &VarNotRequired, 0)) ?
- false : true;
- sprintf(VerString,"%d.%d%c", Version.Number, Version.Rev, Version.Product);
- }
-
-
- /* The following function will not handle reset of other workstations as
- written, as no true key buffer is passed. Will handle begin/end/abort
- transaction, reset & stop. Would also handle version op, but is handled
- by constructor anyway! */
-
- int TBTRecMgr::BT(OP_CODE OpCode, int Key) {
- return BTRV(OpCode, VarPosBlk, &VarNotRequired, &VarNotRequired,
- &VarNotRequired, Key);
- }
-
-
- TAltColSeq::TAltColSeq(FNameStr SpecName) {
- FILE *AltColSequence;
- AltColSequence = fopen(SpecName, "rb");
- fread(&Spec, sizeof(Spec), 1, AltColSequence); //read in the alt col seq
- fclose(AltColSequence);
- }
-
-
- CFileSpec::CFileSpec() {
- Specs = new TFileSpec;
- memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
- }
-
-
- CFileSpec::CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
- TKeyList *AKeyList, int FileFlags, int PreAlloc) {
- Specs = new TFileSpec;
- memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
- Specs->FileSpec.RecLen = RecLen; //Assign basic Btrieve file
- Specs->FileSpec.PageSize = PageSize; //characteristics.
- Specs->FileSpec.NumKeys = NumKeys;
- Specs->FileSpec.FileFlags = FileFlags;
- Specs->FileSpec.PreAlloc = PreAlloc;
- int Counter = 0;
- TKeyList *Keys = KeyList = AKeyList;
- if ( Keys ) {
- do {
- Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyPos =
- Keys->KeySpec.SKeySpec.KeyPos;
- Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyLen =
- Keys->KeySpec.SKeySpec.KeyLen;
- Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyFlags =
- Keys->KeySpec.SKeySpec.KeyFlags;
- Specs->FileSpec.KeyArray[Counter].SKeySpec.ExtKeyType =
- Keys->KeySpec.SKeySpec.ExtKeyType;
- Counter++;
- Keys = Keys->Next;
- } while ( Keys );
- }
- }
-
-
- CFileSpec::~CFileSpec() {
- delete Specs; //Dispose of file specs.
- if ( KeyList ) {
- TKeyList *x1, *x2; //Dispose of linked list of key specs.
- x1 = KeyList;
- while ( x1->Next ) {
- x2 = x1->Next;
- delete x1;
- x1 = x2;
- }
- delete x1;
- }
- }
-
-
- BBase::BBase(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner) {
- memset(&Specs.Entire, 0, sizeof(Specs.Entire));
- memset(PosBlk, 0, sizeof(PosBlk));
- memset(Owner, 0, sizeof(Owner));
- DBufferLen = 0;
-
- //FileBufLen is 16 for filespec + 384 for max key
- //specs + 265 for an alternate collating sequence.
- int FileBufLen = MaxFileSpecLength;
- int KeyBufLen = 384; //Max of 24 keys * 16 bytes per key spec
-
- HasAltCol = false; //initialize to false..reset as needed later
- strcpy(AltColName, ""); //initialize to empty string..reset as needed later
-
- HasOwner = (strlen(owner) == 0) ? false : true;
- strcpy(Owner, owner);
-
- //Now copy DOS filename into object, and assure it's null terminated.
- strcpy(BFileName, UserFileName);
-
- //Open file in specified mode.
- int Status = Open(OpenMode);
- if ( !Status ) { //if Open call went ok, i.e. Status = 0
- Status = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
- if ( !Status ) { //if Stat call went OK...fill data members
- /* Btrieve filespecs and key specs are now in the BBase object!
- FileBufLen will have been changed to size of data buffer returned by
- stat call. Save that value now. */
- SpecLength = FileBufLen;
- NumRecs = Specs.FileSpec.NumRecs[0] +
- Specs.FileSpec.NumRecs[1] * 65536;
-
- IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ?
- true: false;
-
- //Count total number of key segments
- NumSegs = Specs.FileSpec.NumKeys; //Initialize to # of keys. Will
- //increment as needed in next
- //section.
-
- int Counter = 1, Counter1 = 0;
- while (Counter <= Specs.FileSpec.NumKeys)
- do {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented)
- == Segmented) {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
- == AltCol) HasAltCol = true;
- NumSegs++;
- Counter1++;
- }
- else {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
- == AltCol) HasAltCol = true;
- Counter++;
- Counter1++;
- }
- } while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
- == Segmented);
- if (HasAltCol) {
- int AltColNameOffset = 16 + (16 * NumSegs) + 1;
- memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
- AltColName[8] = '\0';
- }
- BStatus = 0; //Stat call went OK. Data members filled now.
- }
- else {
- BStatus = Status; //Open succeeded but stat failed. Put error code
- Close(); //for bad stat in global var BStatus, close file.
- }//if stat call ok
-
- }//if file opened ok
- else
- BStatus = Status; //Assign error code for bad open to global var.
- } //end BBase::BBase
-
-
- int BBase::Open(OPEN_MODE Mode) {
- int OpenStatus;
- if (HasOwner) {
- DBufferLen = strlen(Owner) + 1;
- OpenStatus = BTRV(BOpen, PosBlk, Owner, &DBufferLen, BFileName, Mode);
- }
- else
- OpenStatus = BTRV(BOpen, PosBlk, &VarNotRequired, &VarNotRequired, BFileName, Mode);
- IsOpen = (OpenStatus == 0) ? 1 : 0;
- return OpenStatus;
- }
-
-
- int BBase::Close() {
- if (IsOpen) {
- int CloseStatus = BTRV(BClose, PosBlk, &VarNotRequired, &VarNotRequired,
- &VarNotRequired, NotRequired);
- IsOpen = (CloseStatus == 0) ? 0 : 1;
- return CloseStatus;
- }
- else
- return 0;
- }
-
-
- //File must be open for this call to succeed.
- int BBase:: Stat() {
- memset(&Specs.Entire, 0, sizeof(Specs.Entire));
-
- //FileBufLen is 16 for filespec + 384 for max key
- //specs + 265 for an alternate collating sequence.
- int FileBufLen = MaxFileSpecLength;
- int KeyBufLen = 384; //Max of 24 keys * 16 bytes per key spec
-
- HasAltCol = false; //initialize to false..reset as needed later
- strcpy(AltColName, ""); //initialize to empty string..reset as needed later
-
- BStatus = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
- if ( !BStatus ) { //if Stat call went OK...fill data members
- /* Btrieve filespecs and key specs are now in the BBase object!
- FileBufLen will have been changed to size of data buffer returned by
- stat call. Save that value now. */
- SpecLength = FileBufLen;
- NumRecs = Specs.FileSpec.NumRecs[0] +
- Specs.FileSpec.NumRecs[1] * 65536;
- IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ? true: false;
-
- //Count total number of key segments
- NumSegs = Specs.FileSpec.NumKeys; //Initialize to # of keys. Will
- //increment as needed in next
- //section.
-
- int Counter = 1, Counter1 = 0;
- while (Counter <= Specs.FileSpec.NumKeys)
- do {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented) == Segmented) {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
- HasAltCol = true;
- NumSegs++;
- Counter1++;
- }
- else {
- if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
- HasAltCol = true;
- Counter++;
- Counter1++;
- }
- } while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
- == Segmented);
- if (HasAltCol) {
- int AltColNameOffset = 16 + (16 * NumSegs) + 1;
- memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
- AltColName[8] = '\0';
- }
- }
- return BStatus;
- }
-
-
- BBase::~BBase() {
- Close();
- }
-
-
- BFile::BFile() {
- DBuffer = 0;
- KBuffer = 0;
- }
-
-
- BFile::BFile(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner,
- unsigned int dBufferSize): BBase(UserFileName, OpenMode, owner) {
- DBufferSize = (dBufferSize == 0) ? MaxFixedRecLength : dBufferSize;
- DBuffer = new byte [DBufferSize];
- if ( DBuffer ) memset(DBuffer, 0, DBufferSize);
- KBuffer = new byte [MaxKBufferLength];
- if ( KBuffer ) memset(KBuffer, 0, MaxKBufferLength);
- }
-
-
- int BFile::BT(OP_CODE OpCode, int Key) {
- return BTRV(OpCode, PosBlk, DBuffer, &DBufferLen, KBuffer, Key);
- }
-
-
- int BFile::AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile) {
- int NewSegmentCount = 1;
- boolean SuppIdxHasAltCol;
- TKeyList* AKeyList = KeyList;
- while ( AKeyList->Next ) { //Count # of segments to be in supp index.
- NewSegmentCount++;
- AKeyList = AKeyList->Next;
- }
- if ( (NewSegmentCount + NumSegs) > MaxNumSegments )
- return 1;
- AKeyList = KeyList;
- int Offset = 0;
- do {
- if ( (AKeyList->KeySpec.SKeySpec.KeyFlags & AltCol) == AltCol )
- SuppIdxHasAltCol = true;
- memmove( DBuffer+Offset, AKeyList, KeySpecSize);
- Offset += KeySpecSize;
- AKeyList = AKeyList->Next;
- } while (AKeyList);
- if ( KeyList ) {
- TKeyList *x1, *x2; //Dispose of linked list of key specs.
- x1 = KeyList;
- while ( x1->Next ) {
- x2 = x1->Next;
- delete x1;
- x1 = x2;
- }
- delete x1;
- }
- DBufferLen = KeySpecSize * NewSegmentCount;
- //If the supplemental index is to have an alternate collating sequence, get
- //it in the data buffer, and add its size to DBufferLen parameter.
- if ( strlen(AltColFile) && SuppIdxHasAltCol ) {
- TAltColSeq *ACS = new TAltColSeq(AltColFile);
- memcpy( DBuffer+(KeySpecSize*NewSegmentCount), &ACS->Spec, sizeof(ACS->Spec));
- DBufferLen += sizeof(ACS->Spec);
- delete ACS;
- }
- BStatus = BT(BCrSuppIdx);
- return BStatus;
- }
-
-
- BFile::~BFile() {
- if (DBuffer != 0) delete DBuffer;
- if (KBuffer != 0) delete KBuffer;
- }
-
-
- BFile& BFile::operator++() {
- DBufferLen = DBufferSize;
- BT(BStepNext);
- return *this;
- }
-
-
- BFile& BFile::operator++(int) {
- BT(BInsert); //uses default key (2nd parameter) of 0 as key for positioning
- return *this;
- }
-
-
- BFile& BFile::operator--() {
- BT(BStepPrev);
- return *this;
- }
-
-
- BFile& BFile::operator--(int) {
- BT(BDelete);
- return *this;
- }
-
-
- BFile& BFile::operator=(BFile& bfile) {
- DBufferLen = bfile.DBufferLen;
- memmove(DBuffer, &(*bfile.DBuffer), bfile.DBufferSize);
- return *this;
- }
-
-
- /* ------------------------------------------------------------------------ */
- /* SPECIAL BTC FUNCTIONS */
- /* ------------------------------------------------------------------------ */
- /* ------------------------------------------------------------------------ */
-
- /* CreateFile() */ //See CREATE1.CPP and CREATE2.CPP for examples of usage.
- /* ------------------------------------------------------------------------ */
- int CreateBTFile(FNameStr UserFileName, TFileSpec* UserFileSpec,
- FNameStr AltColFile="", OwnerName Owner="",
- OwnerAccess Access=RQ) {
-
- //Count total # of key segments in UserFileSpec.
- boolean HasAltCol = false;
- int NumSegs = UserFileSpec->FileSpec.NumKeys;
- int Counter = 1, Counter1 = 0;
- while (Counter <= UserFileSpec->FileSpec.NumKeys)
- do {
- if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
- & Segmented) == Segmented) {
- if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
- & AltCol) == AltCol) HasAltCol = true;
- NumSegs++;
- Counter1++;
- }
- else {
- if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
- & AltCol) == AltCol) HasAltCol = true;
- Counter++;
- Counter1++;
- }
- }
- while ((UserFileSpec->FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
- == Segmented);
-
- UserFileSpec->FileSpec.Reserved[1] = 0x00;
- UserFileSpec->FileSpec.Reserved[2] = 0x00;
-
- //If an ACS was specified, get it into the filespec.
- int SpecLength = 16 + (NumSegs * 16);
- if ( strlen(AltColFile) && HasAltCol ) {
- TAltColSeq *AltColObj = new TAltColSeq(AltColFile);
- memcpy( &UserFileSpec->Entire[SpecLength],
- &AltColObj->Spec, sizeof(AltColObj->Spec) );
- SpecLength += sizeof(AltColObj->Spec);
- delete AltColObj;
- }
-
- BStatus = BTRV(BCreate, VarPosBlk, UserFileSpec, &SpecLength, UserFileName, 0);
-
- int ownerLength = strlen(Owner);
- if (ownerLength != 0) {
- BFile *NewFile = new BFile(UserFileName, Accel, "", 9);
- if (!BStatus) {
- if (ownerLength > 8) ownerLength = 8;
- //As there is nothing but nulls in DBuffer and KBuffer, by virtue
- //of the BFile constructor for object NewFile, no need to copy the
- //trailing '\0' in the Owner string...it'll be there already.
- memmove(NewFile->DBuffer, Owner, ownerLength);
- memmove(NewFile->KBuffer, Owner, ownerLength);
- //Let Btrieve's set owner op see a trailing null.
- NewFile->DBufferLen = ++ownerLength;
- BStatus = NewFile->BT(BSetOwner, Access);
- //Next line superfluous w/new destructor for BBase
- //NewFile->Close();
- delete NewFile;
- }
- }
- return BStatus;
- }
-
- /* CloneBTFile() */ //Declared as friend to BFile class.
- /* ------------------------------------------------------------------------ */
-
- //For simplicity, this function assumes the source file for the cloning op is
- //closed. Calling this function when the file is open will cause the function
- //to fail, probably w/code 85, so programmers beware. If the Btrieve status
- //on a bad open is returned by the constructor for CurrentBFile, the CloneFile
- //function will return that value.
-
- //NOTE!!! This function goes beyond the capability of "BUTIL -CLONE" in that
- // this function has flexible handling of supplemental indexes in the
- //clone file (drop, retain, or make them permanent). In addition, if no
- //permanent indexes use an alternate collating sequence, but one or more
- //supplemental indexes DOES use one, the clone can retain the supplemental
- //indexes WITH the alternate collating sequence, duplicating the file
- //structure perfectly. This is something that "BUTIL -CLONE" CANNOT HANDLE!!
-
- int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option=Retain,
- OwnerName Owner="") {
- BBase *CurrentBFile = new BBase(CurrentFile, ReadOnly, Owner);
- if (BStatus) {
- delete CurrentBFile;
- return BStatus;
- }
- CurrentBFile->Specs.FileSpec.FileFlags &= 0xFD; //clear PreAllocate bit
- CurrentBFile->Specs.ReturnFileSpec.UnusedPgs = 0;
- int NewSpecLength = CurrentBFile->SpecLength;
- int NewNumKeys = CurrentBFile->Specs.FileSpec.NumKeys;
-
- boolean *SuppIdxList = new boolean[24];
- boolean *SuppIdxHasAltCol = new boolean[24];
- memset(SuppIdxList, false, 48);
- memset(SuppIdxHasAltCol, false, 48);
- boolean HasSuppIdx = false, permKeyHasAltCol = false;
- int NumberSuppSegs = 0, NumberSuppIdx = 0, NewOffset = 16, Counter;
- TKeySpec *SuppIdx = new TKeySpec[CurrentBFile->NumSegs];
-
- TFileSpec *NewFileSpec = new TFileSpec;
- memset( NewFileSpec->Entire, 0, sizeof(*NewFileSpec) );
- memcpy( NewFileSpec->Entire, &CurrentBFile->Specs, 16 );
-
-
- /* In this section, determine if there are any supplemental indexes in the
- source Btrieve file. If so, set boolean indicator HasSuppIdx (which
- has function-wide scope) to true. For each key segment (0 to 23)
- identified as supplemental, set a corresponding boolean in an array
- (SuppIdxList[24]) to true. Get a count of supplemental indexes
- (NumberSuppIdx), and a count of the total number of supplemental index
- segments (NumberSuppSegs). Populate an array of keyspecs (SuppIdx[24])
- with the specs for all supplemental index segments.*/
-
- for ( Counter=0; Counter < CurrentBFile->NumSegs; Counter++) {
- int KeyFlags = CurrentBFile->Specs.FileSpec.KeyArray[Counter].SKeySpec.KeyFlags;
- if ( ((KeyFlags & AltCol) == AltCol) && ((KeyFlags & Supplemental) != Supplemental))
- permKeyHasAltCol = true;
- if ( (KeyFlags & Supplemental ) == Supplemental) {
- if ((KeyFlags & AltCol) == AltCol)
- SuppIdxHasAltCol[NumberSuppSegs] = true;
- HasSuppIdx = true;
- SuppIdxList[Counter] = true;
- //Next line sets one structure equal to another.
- SuppIdx[NumberSuppSegs] = CurrentBFile->Specs.FileSpec.KeyArray[Counter];
- //Zero supplemental bit.
- SuppIdx[NumberSuppSegs].SKeySpec.KeyFlags &= 0xFF7F;
- NumberSuppSegs++; //increment count of supplemental segments
- if ( (KeyFlags & Segmented) != Segmented) NumberSuppIdx++;
- }
- }
-
- if ( ((Option==Drop) || (Option==Retain)) && HasSuppIdx ) {
- int Counter1 = 0;
- for (Counter=1; Counter <= CurrentBFile->Specs.FileSpec.NumKeys; Counter++) {
- if ( SuppIdxList[Counter1] ) NewNumKeys--;
- do {
- if ( !SuppIdxList[Counter1] ) {
- NewFileSpec->FileSpec.KeyArray[Counter1] =
- CurrentBFile->Specs.FileSpec.KeyArray[Counter1];
- NewOffset += 16;
- }
- else
- NewSpecLength -= 16;
- Counter1++;
- } while
- ( (CurrentBFile->Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags
- & Segmented) == Segmented );
- }
- NewFileSpec->FileSpec.NumKeys = NewNumKeys;
- if ( CurrentBFile->HasAltCol )
- memmove( &NewFileSpec->Entire[NewOffset],
- &CurrentBFile->Specs.Entire[ 16 + (CurrentBFile->NumSegs * 16)], 265 );
- //Next line executed if source file has supplemental indexes, and if
- //option chosen was to either drop or retain them.
- BStatus = BTRV(BCreate, VarPosBlk, &NewFileSpec->Entire, &NewSpecLength,
- NewFile, 0);
- } //end if
-
- /* If retaining the supplemental indexes AS supplemental indexes, then at
- this point we're ready to add them to the newly created file. */
-
- if ( (Option == Retain) && HasSuppIdx ) {
- BFile *NewBFile = new BFile( NewFile, Accel, "", MaxFileSpecLength );
- int Counter1 = 0, DBuffOffset = 0;
- for ( Counter=1; Counter<=NumberSuppIdx; Counter++) {
- do {
- memmove( NewBFile->DBuffer+DBuffOffset, &SuppIdx[Counter1], 16 );
- DBuffOffset += 16;
- Counter1++;
- } while ( (SuppIdx[Counter1-1].SKeySpec.KeyFlags & Segmented) == Segmented );
- NewBFile->DBufferLen = Counter1 * 16;
- if (SuppIdxHasAltCol[Counter1-1] && (!permKeyHasAltCol)) {
- memmove(NewBFile->DBuffer+DBuffOffset,
- &(CurrentBFile->Specs.Entire[CurrentBFile->SpecLength-265]), 265);
- NewBFile->DBufferLen += 265;
- }
- BStatus = NewBFile->BT(BCrSuppIdx);
- memset( NewBFile->DBuffer, 0, MaxFileSpecLength );
- DBuffOffset++;
- } //end for
- //Next line superfluous w/new destructor for BBase.
- //NewBFile->Close();
- delete NewBFile;
- } //end if
-
- /* WARNING! If user program specified 'None' and there actually ARE one or
- more supplemental indexes in the source file, they WILL be retained in the
- target file, as permanent indexes! This can be done intentionally if
- desired. */
- if ( (Option==None) || ( (Option==Retain) && !HasSuppIdx ) ||
- ( (Option==Drop) && !HasSuppIdx ) )
- BStatus = BTRV(BCreate, VarPosBlk, &CurrentBFile->Specs,
- &CurrentBFile->SpecLength, NewFile, 0);
-
- //Next line superfluous w/new destuctor for BBase
- //CurrentBFile->Close();
- delete NewFileSpec; //Note NewFileSpec would not have been used if
- //HandleSupps parameter to this function was 'None'
- delete SuppIdx;
- delete SuppIdxHasAltCol;
- delete SuppIdxList;
- delete CurrentBFile;
- return BStatus;
- }
-
- /* NewKeySpec() */
- /* ------------------------------------------------------------------------ */
- // NewKeySpec() below is frequently used together with CreateBTFile(). See
- // CREATE1.CPP and CREATE2.CPP.
-
- TKeyList* NewKeySpec(int KPos, int KLen, int KFlags, byte EType,
- TKeyList *NextKey = 0) {
- TKeyList *TheKeyList = new TKeyList;
- memset(TheKeyList, 0, sizeof(*TheKeyList));
- TheKeyList->KeySpec.SKeySpec.KeyPos = KPos;
- TheKeyList->KeySpec.SKeySpec.KeyLen = KLen;
- TheKeyList->KeySpec.SKeySpec.KeyFlags = KFlags;
- TheKeyList->KeySpec.SKeySpec.ExtKeyType = EType;
- TheKeyList->Next = NextKey;
- return TheKeyList;
- }
-
-
- /* BtrieveIsLoaded() */
- /* ------------------------------------------------------------------------ */
- int BtrieveIsLoaded() {
- TBTVersion V;
- int sizeV = sizeof(V);
- return ( (BTRV( BVersion, VarPosBlk, &V, &sizeV, &VarNotRequired, 0 ))
- == BtrieveNotLoaded ) ? false : true;
- }
-
-
- //end BTC.CPP
-